//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_issue_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_entry_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_issue"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_entry_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_issue_api"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectIssueApiImpl) ListAttrValue(ctx context.Context, req *project_issue_api.ListAttrValueRequest) (*project_issue_api.ListAttrValueResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.ListAttrValueResponse{
			Code:   project_issue_api.ListAttrValueResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.ListAttrValueResponse{
			Code:   project_issue_api.ListAttrValueResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.ListAttrValueResponse{
			Code:   project_issue_api.ListAttrValueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	valueList, err := issue_dao.IssueDao.Distinct(ctx, req.ProjectId, req.AttrKey)
	if err != nil {
		return nil, err
	}
	return &project_issue_api.ListAttrValueResponse{
		Code:      project_issue_api.ListAttrValueResponse_CODE_OK,
		ValueList: valueList,
	}, nil
}

func (apiImpl *ProjectIssueApiImpl) LinkSprit(ctx context.Context, req *project_issue_api.LinkSpritRequest) (*project_issue_api.LinkSpritResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.LinkSpritResponse{
			Code:   project_issue_api.LinkSpritResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.LinkSpritResponse{
			Code:   project_issue_api.LinkSpritResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.LinkSpritResponse{
			Code:   project_issue_api.LinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//只有管理员可以进行迭代关联
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_issue_api.LinkSpritResponse{
			Code:   project_issue_api.LinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	issueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return &project_issue_api.LinkSpritResponse{
			Code:   project_issue_api.LinkSpritResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}
	entryItem, err := project_entry_dao.EntryDao.Get(ctx, req.SpritId, req.ProjectId)
	if err != nil {
		return &project_issue_api.LinkSpritResponse{
			Code:   project_issue_api.LinkSpritResponse_CODE_NO_SPRIT,
			ErrMsg: "迭代不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
		return &project_issue_api.LinkSpritResponse{
			Code:   project_issue_api.LinkSpritResponse_CODE_NO_SPRIT,
			ErrMsg: "迭代不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.IssueDao.SetSprit(sessCtx, req.ProjectId, req.IssueId, req.SpritId, entryItem.CreateTime, nowTime)
		if err != nil {
			return nil, err
		}
		if issueItem.IssueType == int32(project_issue_api.ISSUE_TYPE_ISSUE_TYPE_TASK) {
			err = issue_dao.SpritStateDao.MarkTaskCountDirty(sessCtx, req.SpritId)
			if err != nil {
				return nil, err
			}
		} else if issueItem.IssueType == int32(project_issue_api.ISSUE_TYPE_ISSUE_TYPE_BUG) {
			err = issue_dao.SpritStateDao.MarkBugCountDirty(sessCtx, req.SpritId)
			if err != nil {
				return nil, err
			}
		}
		return &project_issue_api.LinkSpritResponse{
			Code: project_issue_api.LinkSpritResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addLinkSpritEvent(sessionItem, req, projectItem, issueItem, entryItem)

	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.SetSpritNotice{
		ProjectId:  req.ProjectId,
		IssueId:    req.IssueId,
		OldSpritId: issueItem.SpritId,
		NewSpritId: req.SpritId,
	})
	return ret.(*project_issue_api.LinkSpritResponse), nil
}

func (apiImpl *ProjectIssueApiImpl) CancelLinkSprit(ctx context.Context, req *project_issue_api.CancelLinkSpritRequest) (*project_issue_api.CancelLinkSpritResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.CancelLinkSpritResponse{
			Code:   project_issue_api.CancelLinkSpritResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.CancelLinkSpritResponse{
			Code:   project_issue_api.CancelLinkSpritResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.CancelLinkSpritResponse{
			Code:   project_issue_api.CancelLinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	//只有管理员可以进行取消迭代关联
	if !(projectItem.OwnerUserId == sessionItem.UserId || roleItem.BasicInfo.Admin) {
		return &project_issue_api.CancelLinkSpritResponse{
			Code:   project_issue_api.CancelLinkSpritResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	issueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return &project_issue_api.CancelLinkSpritResponse{
			Code:   project_issue_api.CancelLinkSpritResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}
	if issueItem.SpritId == "" {
		return &project_issue_api.CancelLinkSpritResponse{
			Code: project_issue_api.CancelLinkSpritResponse_CODE_OK,
		}, nil
	}

	entryItem, err := project_entry_dao.EntryDao.Get(ctx, issueItem.SpritId, req.ProjectId)
	if err != nil {
		return &project_issue_api.CancelLinkSpritResponse{
			Code:   project_issue_api.CancelLinkSpritResponse_CODE_NO_SPRIT,
			ErrMsg: "迭代不存在",
		}, nil
	}
	if entryItem.EntryType != uint32(project_entry_api.ENTRY_TYPE_ENTRY_TYPE_SPRIT) {
		return &project_issue_api.CancelLinkSpritResponse{
			Code:   project_issue_api.CancelLinkSpritResponse_CODE_NO_SPRIT,
			ErrMsg: "迭代不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.IssueDao.SetSprit(sessCtx, req.ProjectId, req.IssueId, "", 0, nowTime)
		if err != nil {
			return nil, err
		}
		if issueItem.IssueType == int32(project_issue_api.ISSUE_TYPE_ISSUE_TYPE_TASK) {
			err = issue_dao.SpritStateDao.MarkTaskCountDirty(sessCtx, entryItem.EntryId)
			if err != nil {
				return nil, err
			}
		} else if issueItem.IssueType == int32(project_issue_api.ISSUE_TYPE_ISSUE_TYPE_BUG) {
			err = issue_dao.SpritStateDao.MarkBugCountDirty(sessCtx, entryItem.EntryId)
			if err != nil {
				return nil, err
			}
		}
		return &project_issue_api.CancelLinkSpritResponse{
			Code: project_issue_api.CancelLinkSpritResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addCancelLinkSpritEvent(sessionItem, projectItem, issueItem, entryItem)

	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.SetSpritNotice{
		ProjectId:  req.ProjectId,
		IssueId:    req.IssueId,
		OldSpritId: issueItem.SpritId,
		NewSpritId: "",
	})
	return ret.(*project_issue_api.CancelLinkSpritResponse), nil
}
